using System;
using System.Diagnostics;
using System.Reflection;
using System.Text;
namespace CSUtils
{
    public static class CLog
    {
        public static ILog logObj{get;private set;}

        public static Action<byte, string, string, string, string, string> onLogEvent;
        public static Action<CLogType, string, string> onLogUploadEvent;

        public static void LogUpload(CLogType type, string log, string url = "", string colorStr = null)
        {
            onLogUploadEvent?.Invoke(type, log, url);
        }

        public static void Init(ILog logObj)
        {
            CLog.logObj = logObj;
        }

        //[Conditional("ShowDebugLog")]
        public static void i(string tag, string msg, bool isShowStackTrace = true, string colorStr = null)
        {
            log(TLogType.Log, tag, msg, isShowStackTrace, colorStr);
        }

        //[Conditional("ShowDebugLog")]
        public static void I(string tag, string msg, string stackTrace, bool isAddStackTrace = false, string colorStr = null)
        {
            LogStackTrace(TLogType.Log, tag, msg, stackTrace, isAddStackTrace, colorStr);
        }

        public static void W(string tag, string msg, bool isShowStackTrace = false, string colorStr = null)
        {
            log(TLogType.Warning, tag, msg, isShowStackTrace, colorStr);
        }

        public static void E(string tag, string msg, bool isShowStackTrace = true, string colorStr = null)
        {
            log(TLogType.Error, tag, msg, isShowStackTrace, colorStr);
        }

        public static void Ee(string tag, Exception ex, bool isShowStackTrace = true, string colorStr = null)
        {
            Ee(tag, "", ex, isShowStackTrace, colorStr);
        }

        public static void Ee(string tag, string msg, bool isShowStackTrace = true, string colorStr = null)
        {
            log(TLogType.ExceptionError, tag, msg, isShowStackTrace);
        }

        public static void Ee(string tag, string msg, Exception ex, bool isShowStackTrace = true, string colorStr = null)
        {
            string stackTrace = "";
            if(isShowStackTrace)
            {
                stackTrace = GetStackTrace("", null, 3);
            }
            LogStackTrace(TLogType.ExceptionError, tag, msg + "..." + ex?.Message, ex?.GetInfo(0, stackTrace), false, colorStr);
        }

        public static void Ex(string tag, Exception ex, string colorStr = null)
        {
            Ex(tag, "错误", ex, colorStr);
        }

        public static void Ex(string tag, string ex, string colorStr = null)
        {
            log(TLogType.Exception, tag, ex, true, colorStr);
        }

        public static void Ex(string tag, string msg, Exception ex, string colorStr = null)
        {
            if(ex == null)
            {
                LogStackTrace(TLogType.Exception, tag, msg, null, true, colorStr);
            } else
            {
                LogStackTrace(TLogType.Exception, tag, msg + $"...{ex.Message}", ex.GetInfo(), true, colorStr);
            }
        }

        public static void Ex(string tag, string msg, Exception ex, StackTrace lastStackTrace, string colorStr = null)
        {
            var lastStackTraceStr = GetStackTrace("", lastStackTrace);
            if(ex == null)
            {
                LogStackTrace(TLogType.Exception, tag, msg, null, false, colorStr);
            } else
            {
                LogStackTrace(TLogType.Exception, tag, msg + "__" + ex.Message, ex.GetInfo(0, lastStackTraceStr), false, colorStr);
            }
        }

        public static void log(byte type, string tag, string msg, bool isShowStackTrace = false, string colorStr = null)
        {
            string stackTrace = "";
            if(isShowStackTrace)
            {
                stackTrace = GetStackTrace("", null, 3);
            }
            _FunLog(type, tag, null, msg, stackTrace, colorStr);
        }

        public static void LogStackTrace(byte type, string tag, string msg, string stackTraceStr, bool isAddStackTrace = false, string colorStr = null)
        {
            if(isAddStackTrace)
            {
                stackTraceStr += GetStackTrace("", null, 1);
            }
            _FunLog(type, tag, null, msg, stackTraceStr, colorStr);
        }

        public static void _FunLog(byte type, string tag, string time, string log, string stackTrace, string colorStr)
        {
            logObj?._SLog(type, tag, time, log, stackTrace, colorStr);
            try
            {
                onLogEvent?.Invoke(type, tag, time, log, stackTrace, colorStr);
            } catch {}
        }

        public static string GetInfo(this Exception ex, int shieldLine = 0, string end = "")
        {
            var st = new StackTrace(ex, true);
            var msg2 = $"StackTrace={ex.StackTrace}";
            return GetStackTrace(msg2, st, shieldLine, end);
        }

        static bool isMono = true;

        public static string GetStackTrace(string msg, StackTrace st = null, int shieldLine = 0, string end = "")
        {
            if(isMono)
            {
                if(st == null)
                {
                    st = new StackTrace(1, true);
                }
                return msg + "\n" + st;
            }
            if(st == null)
            {
                st = new StackTrace(true);
            }
            if(string.IsNullOrEmpty(msg) == false)
            {
                msg = msg + "\nstackTrace==";
            }
            var ssb = new StringBuilder(msg);
            StackFrame[] frameArr = st.GetFrames();
            for(int i = shieldLine; i < frameArr.Length; i++)
            {
                var stackFrame = frameArr[i];
                string _fileName = stackFrame.GetFileName();
                if(string.IsNullOrEmpty(_fileName))
                {
                    continue;
                }
                MethodBase method = stackFrame.GetMethod();
                string methodName = "null";
                if(method != null && method.Name != null)
                {
                    methodName = method.ToString();
                }
                string fileName0 = _fileName.Replace("\\", "/").Substring(0);
                int index = fileName0.IndexOf("Assets/", StringComparison.Ordinal);
                if(index > 0)
                {
                    fileName0 = fileName0.Substring(index);
                }
                int lineNumber = stackFrame.GetFileLineNumber();
                ssb.Append($"{methodName} (at {fileName0}:{lineNumber})\n");
            }
            ssb.Append("\n");
            ssb.Append(end);
            return ssb.ToString();
        }
    }
    public interface ILog
    {
        void _SLog(byte type, string tag, string time, string logStr, string stackTrace, string colorStr);
    }
    public enum CLogType
    {
        Error = 0, Assert = 1, Warning = 2, Log = 3, Exception = 4,
        ExceptionError = 5
    }
    public class TLogType
    {
        public const byte Error = 0;
        public const byte Assert = 1;
        public const byte Warning = 2;
        public const byte Log = 3;
        public const byte Exception = 4;
        public const byte ExceptionError = 5;
    }
}
